package com.ecoolex.ying.space.core.manager;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.ying.space.core.dao.GoodsClassifyDAO;
import com.ecoolex.ying.space.core.service.PickGoodsSearchService;
import com.ecoolex.ying.space.entity.GoodsClassify;
import com.ecoolex.ying.space.entity.GoodsClassify.Column;
import com.ecoolex.ying.space.entity.GoodsClassifyExample;
import com.ecoolex.ying.space.pojo.QueryGoodsClassifyDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import static com.ecoolex.ying.space.entity.GoodsClassify.*;

@Service
public class GoodsClassifyManager {
    @Autowired
    private GoodsClassifyDAO dao;

    @Autowired
    private GoodsManager goodsManager;
    @Autowired
    private PickGoodsManager pickGoodsManager;

    @Autowired
    private PickGoodsSearchService pickGoodsSearchService;


    private GoodsClassify verify(GoodsClassify record) {
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getName()), ResultCode.VERIFY.build(10), "名称不能为空");
        if (Check.isNullOrLtOne(record.getParentClassifyId())) {
            return null;
        } else {
            GoodsClassify parent = getById(record.getParentClassifyId());
            BizAssert.isTrue(Check.notNull(parent), ResultCode.BIZ.build(1), "父级分类不存在");
            return parent;
        }
    }

    public GoodsClassify create(GoodsClassify record, String createUser) {
        GoodsClassify parent = verify(record);
        if (Check.isNull(parent)) {
            record.setParentClassifyId(0);
            record.setLevel(1);
        } else {
            record.setParentClassifyId(parent.getClassifyId());
            record.setLevel(parent.getLevel() + 1);
        }
        record.setIsShow(false);
        record.setDeleted(NOT_DELETED);
        record.setUpdateUser(createUser);
        record.setUpdateTime(Date.from(Instant.now()));
        record.setCreateUser(createUser);
        record.setCreateTime(Date.from(Instant.now()));
        dao.insert(record);
        return record;
    }

    @Transactional
    public void update(GoodsClassify record, String updateUser) {
        verify(record);

        GoodsClassify old = getById(record.getClassifyId());

        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));
        int row = dao.updateByPrimaryKeySelective(record,
                Column.excludes(Column.parentClassifyId,
                        Column.level,
                        Column.isShow,
                        Column.deleted,
                        Column.createUser,
                        Column.createTime));

        BizAssert.isTrue(row == 1, "修改分类失败");

        pickGoodsSearchService.changeClassify(old, record);
    }

    public void delete(GoodsClassify record, String updateUser) {
        // 是否存在子分类
        long childNumber = countByParent(record.getClassifyId());
        BizAssert.isTrue(childNumber == 0, ResultCode.VERIFY.build(10), "当前分类存在{}个子分类, 无法删除", childNumber);
        // 检查商品是否关联
        long goodsUsedNumber = goodsManager.countByClassifyId(record.getClassifyId());
        BizAssert.isTrue(goodsUsedNumber == 0, ResultCode.VERIFY.build(11), "当前分类存在{}个商品关联, 无法删除", goodsUsedNumber);
        long pickGoodsUsedNumber = pickGoodsManager.countByClassifyId(record.getClassifyId());
        BizAssert.isTrue(pickGoodsUsedNumber == 0, ResultCode.VERIFY.build(12), "当前分类存在{}个优选商品关联, 无法删除", pickGoodsUsedNumber );

        record.setDeleted(IS_DELETED);
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));
        dao.updateByPrimaryKeySelective(record,
                Column.deleted,
                Column.updateUser,
                Column.updateTime);
    }

    private long countByParent(Integer parentClassifyId) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        example.createCriteria()
                .andParentClassifyIdEqualTo(parentClassifyId)
                .andDeletedEqualTo(NOT_DELETED);
        return dao.countByExample(example);
    }

    public GoodsClassify getById(Integer classifyId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(classifyId, NOT_DELETED);
    }

    public List<GoodsClassify> queryAllParent(Boolean isShow) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        GoodsClassifyExample.Criteria criteria = example.createCriteria();
        criteria.andParentClassifyIdEqualTo(0);

        if (Check.notNull(isShow)) {
            criteria.andIsShowEqualTo(isShow);
        }

        criteria.andDeletedEqualTo(NOT_DELETED);
        example.orderBy(Column.sorting.asc());

        return dao.selectByExample(example);
    }

    public List<GoodsClassify> queryByParentId(Integer parentClassifyId, Boolean isShow) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        GoodsClassifyExample.Criteria criteria = example.createCriteria();
        criteria.andParentClassifyIdEqualTo(parentClassifyId);

        if (Check.notNull(isShow)) {
            criteria.andIsShowEqualTo(isShow);
        }

        criteria.andDeletedEqualTo(NOT_DELETED);
        example.orderBy(Column.sorting.asc());

        return dao.selectByExample(example);
    }

    public List<GoodsClassify> queryAll(Boolean isShow) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        GoodsClassifyExample.Criteria criteria = example.createCriteria();

        if (Check.notNull(isShow)) {
            criteria.andIsShowEqualTo(isShow);
        }

        criteria.andDeletedEqualTo(NOT_DELETED);

        return dao.selectByExample(example);
    }

    public Pagination<GoodsClassify> query(QueryGoodsClassifyDTO query, Sorting[] sorts, Page page) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        GoodsClassifyExample.Criteria criteria = example.createCriteria();

        if (Check.notNull(query.getParentClassifyId())) {
            criteria.andParentClassifyIdEqualTo(query.getParentClassifyId());
        }
        if (Check.notNull(query.getLevel())) {
            criteria.andLevelEqualTo(query.getLevel());
        }
        if (Check.notNullOrTrimEmpty(query.getName())) {
            criteria.andNameLike('%' + query.getName()
                    + '%');
        }
        if (Check.notNull(query.getIsShow())) {
            criteria.andIsShowEqualTo(query.getIsShow());
        }

        criteria.andDeletedEqualTo(NOT_DELETED);

        example.orderBy(Sortings.builder(sorts).verify(Column::valueOf).toSql());
        example.setOffset(page.getFirstIndex());
        example.setRows(page.getPageSize());

        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExample(example));
    }

    public Pagination<GoodsClassify> queryClassifyForH5(Integer parentClassifyId, Page page) {
        GoodsClassifyExample example = new GoodsClassifyExample();
        GoodsClassifyExample.Criteria criteria = example.createCriteria();
        criteria.andParentClassifyIdEqualTo(parentClassifyId).andIsShowEqualTo(true).andDeletedEqualTo(NOT_DELETED);
        example.setOffset(page.getFirstIndex());
        example.setRows(page.getPageSize());
        example.orderBy(Column.sorting.desc());
        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExample(example));
    }

    public void show(GoodsClassify record, String updateUser) {
        record.setIsShow(true);
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        GoodsClassifyExample example = new GoodsClassifyExample();
        example.createCriteria().andClassifyIdEqualTo(record.getClassifyId()).andIsShowEqualTo(false).andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.isShow,
                Column.updateUser,
                Column.updateTime );

        BizAssert.isTrue(row == 1, "设置展示失败");
    }

    public void hide(GoodsClassify record, String updateUser) {
        record.setIsShow(false);
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        GoodsClassifyExample example = new GoodsClassifyExample();
        example.createCriteria().andClassifyIdEqualTo(record.getClassifyId()).andIsShowEqualTo(true).andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.isShow,
                Column.updateUser,
                Column.updateTime );

        BizAssert.isTrue(row == 1, "设置隐藏失败");
    }
}